#include"data.hpp"
#include"httplib.h"

namespace aod{
#define WWWROOT "./www"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"
	TableVideo *tb_video=NULL;//httplib基于多线程，数据管理对象需要在多线程中访问，便于访问定义全局变量
	class Server{//业务处理模块类
		private:
			int _port;//服务器的监听端口
			httplib::Server _srv;//搭建http服务器
		private:
			static void Insert(const httplib::Request &req,httplib::Response &rsp){//上传视频
				// 管理员才能进行操作
				if (check_user(req) != "admin") return;

				if(req.has_file("name")==false ||
				   req.has_file("info")==false ||
				   req.has_file("video")==false ||
				   req.has_file("image")==false){
					rsp.status=400;//坏的请求--客户端错误
					rsp.body=R"({"result":false,"reason":"上传的数据信息错误"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				   }
				httplib::MultipartFormData name=req.get_file_value("name");//视频名称
				httplib::MultipartFormData info=req.get_file_value("info");//视频简介
				httplib::MultipartFormData video=req.get_file_value("video");//视频文件
				httplib::MultipartFormData image=req.get_file_value("image");//图片文件
				//MultipartFormData {name--字段名,content_type--正文类型,filename--文件名,content--文件数据}
				std::string video_name=name.content;
				std::string video_info=info.content;
				std::string root=WWWROOT;
				std::string video_path=root+VIDEO_ROOT+video_name+video.filename;
				std::string image_path=root+IMAGE_ROOT+video_name+image.filename;// ./www/image/变形金刚a.jpg

				if(FileUtil(video_path).SetContent(video.content)==false){
					rsp.status=500;
					rsp.body=R"({"result":false,"reason":"视频文件存储失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				if(FileUtil(image_path).SetContent(image.content)==false){
					rsp.status=500;
					rsp.body=R"({"result":false,"reason":"图片文件存储失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				Json::Value video_json;
				video_json["name"]=video_name;
				video_json["info"]=video_info;
				video_json["video"]=VIDEO_ROOT+video_name+video.filename;//相对路径 /video/变形金刚robot.mp4
				video_json["image"]=IMAGE_ROOT+video_name+image.filename;//相对路径 /video/变形金刚a.jpg
				if(tb_video->Insert(video_json)==false){
					rsp.status=500;
					rsp.body=R"({"result":false,"reason":"数据库新增数据失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				rsp.set_redirect("/index.html",303);
				return ;
			}
			static void Delete(const httplib::Request &req,httplib::Response &rsp){//删除视频
				// 管理员才能进行操作
				if (check_user(req) != "admin") return;
				//1.获取要删除的视频ID
				int video_id=std::stoi(req.matches[1]);
				//2.删除视频和图片文件
				Json::Value video;
				if(tb_video->SelectOne(video_id,&video)==false){
					rsp.status=500;
					rsp.body=R"({"result":false,"reason":"不存在视频信息"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				std::string root=WWWROOT;
				std::string video_path=root+video["video"].asString();
				std::string image_path=root+video["image"].asString();
				remove(video_path.c_str());
				remove(image_path.c_str());
				//3.删除数据库信息
				if(tb_video->Delete(video_id)==false){
					rsp.status=500;
					rsp.body=R"({"result":false,"reason":"删除数据库信息失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				return ;
			}
			static void Update(const httplib::Request &req,httplib::Response &rsp){//更新视频信息
				// 管理员才能进行操作
				if (check_user(req) != "admin") return;
				//1.获取要修改的视频信息 1.视频ID 2.修改后的信息
				int video_id=std::stoi(req.matches[1]);
				Json::Value video;
				if(JsonUtil::UnSerialize(req.body,&video)==false){
					rsp.status=400;
					rsp.body=R"({"result":false,"reason":"新的视频信息格式解析失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				//2.修改数据库数据
				if(tb_video->Update(video_id,video)==false){
					rsp.status=500;
					rsp.body=R"({"result":false,"reason":"修改数据库信息失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				return ;
			}
			static void SelectOne(const httplib::Request &req,httplib::Response &rsp){//查找指定视频
				rsp.set_header("Content-Type","application/json");
				// 登录才能进行操作
				if (check_user(req).empty()) {
					rsp.body=R"({"result":false,"reason":"login"})";
					return ;
				}
				//1.获取视频ID
				int video_id=std::stoi(req.matches[1]);
				std::cout << "调用该函数" << video_id << std::endl;
				//2.在数据库中查询指定视频信息
				Json::Value video;
				if(tb_video->SelectOne(video_id,&video)==false){
					rsp.body=R"({"result":false,"reason":"查询数据库指定信息失败"})";
					rsp.set_header("Content-Type","application/json");
					return ;
				}
				//3.组织响应正文--json格式的字符串
				JsonUtil::Serialize(video,&rsp.body);
				std::cout << rsp.body << "2" << std::endl;
				rsp.set_header("Content-Type","application/json");
				return;
			}
			static void SelectAll(const httplib::Request &req,httplib::Response &rsp){//展示所有视频
				rsp.set_header("Content-Type","application/json");
				// 登录才能进行操作
				if (check_user(req).empty()) {
					rsp.body=R"({"result":false,"reason":"login"})";
					return ;
				}
				//  /video    &    /video?search="关键字"
				bool select_flag=true;//默认所有查询
				std::string search_key;
				if(req.has_param("search")==true){
					select_flag=false;//模糊匹配
					search_key=req.get_param_value("search");
				}
				Json::Value videos;
				if(select_flag==true){
					if(tb_video->SelectAll(&videos)==false){
						rsp.body=R"({"result":false,"reason":"查询数据库所有视频信息失败"})";
						return ;
					}
				}
				else{
					if(tb_video->SelectLike(search_key,&videos)==false){
						rsp.body=R"({"result":false,"reason":"查询数据库匹配视频信息失败"})";
					return ;
					}
				}
				//组织响应正文--json格式的字符串
				JsonUtil::Serialize(videos,&rsp.body);
			}
			// 用户登录
			static void Login(const httplib::Request &req,httplib::Response &rsp) {
				Json::Value arg;
				if (!JsonUtil::UnSerialize(req.body, &arg)) return;
				std::string username = arg["username"].asCString();
				std::string password = arg["password"].asCString();

				Json::Value user;
				rsp.set_header("Content-Type","application/json");
				if (!tb_video->GetUser(username, user)) {
					rsp.body=R"({"result":false,"reason":"用户名或密码错误"})";
					return;
				}
				if (password != user["password"].asCString()) {
					rsp.body=R"({"result":false,"reason":"用户名或密码错误"})";
					return;
				}
				rsp.body=R"({"result":true})";
				// 创建session cookies，保存用户会话
				rsp.set_header("Set-Cookie", "username=" + username);
			}
			// 验证用户登录状态
			static std::string check_user(const httplib::Request &req) {
				auto cookie = req.get_header_value("Cookie");
				auto token = std::string("username=");
				auto pos = cookie.find(token);
				if (pos == std::string::npos) return "";
				pos += token.length();
				auto end = cookie.find(';', pos);
				if (end != std::string::npos) end -= pos;
				return cookie.substr(pos, end /** count */);
			}
			// 用户注册
			static void Register(const httplib::Request &req,httplib::Response &rsp) {
				Json::Value arg;
				if (!JsonUtil::UnSerialize(req.body, &arg)) return;

				Json::Value user;
				rsp.set_header("Content-Type","application/json");
				if (tb_video->GetUser(arg["username"].asCString(), user)) {
					rsp.body=R"({"result":false,"reason":"用户名已经存在"})";
					return;
				}
				if (!tb_video->InsertUser(arg)) {
					rsp.body=R"({"result":false,"reason":"创建用户出错"})";
					return;
				}
				rsp.body=R"({"result":true})";
			}
		public:
			Server(int port):_port(port){};
			bool RunModule(){//建立请求与处理函数的映射关系，设置静态资源根目录，启动服务器
				//1.初始化操作--初始化数据管理模块，创建指定的目录
				tb_video=new TableVideo();
				FileUtil(WWWROOT).CreateDirectory();
				std::string root=WWWROOT;
				std::string video_real_path=root+VIDEO_ROOT;// ./www/video
				FileUtil(video_real_path).CreateDirectory();
				std::string image_real_path=root+IMAGE_ROOT;// ./www/image
				FileUtil(image_real_path).CreateDirectory();
				//2.搭建http服务器，开始运行
				//  1.设置静态资源根目录
				_srv.set_mount_point("/",WWWROOT);
				//  2.添加请求-处理函数映射关系
				//正则表达式中：\d表示数字，+表示匹配前边的字符一次或多次，()表示单独捕捉数据
				_srv.Post("/video",Insert);
				_srv.Delete("/video/(\\d+)",Delete);
				_srv.Put("/video/(\\d+)",Update);
				_srv.Get("/video/(\\d+)",SelectOne);
				_srv.Get("/video",SelectAll);
				_srv.Post("/login",Login);
				_srv.Post("/register",Register);
				//  3.启动服务器
				_srv.listen("0.0.0.0",_port);
				return true;
			}
	};
}
